<script>
  import draggable from 'vuedraggable';
  import render from './custom/render';
  import { getSimpleId } from './utils/IdGenerate';
  import { dynamicTableAllowedItems, tableAllowedItems } from './custom/formConf';
  import dynamicTable from './dynamic/dynamicTable';
  import dynamicTableItem from './dynamic/dynamicTableItem';
  import fancyTable from './table/fancyTable';
  import fancyTableItem from './table/fancyTableItem';
  /**
   * 动态表单允许增加的组件列表
   */
  const components = {
    itemBtns(h, element, parent) {
      const { copyItem, deleteItem } = this.$listeners;
      return [
        <span
          class="drawing-item-copy"
          title="复制"
          onClick={(event) => {
            copyItem(element, parent);
            event.stopPropagation();
          }}
        >
          <i class="el-icon-copy-document" />
        </span>,
        <span
          class="drawing-item-delete"
          title="删除"
          onClick={(event) => {
            deleteItem(element, parent);
            event.stopPropagation();
          }}
        >
          <i class="el-icon-delete" />
        </span>
      ];
    }
  };
  const layouts = {
    colItem(h, element, parent) {
      let className =
        this.activeItem.id === element.id ? 'drawing-item active-from-item' : 'drawing-item';
      let labelWidth = element.labelWidth ? `${element.labelWidth}px` : null;
      const { onActiveItemChange } = this.$listeners;
      return (
        <el-col
          class={className}
          span={element.span}
          nativeOnClick={(event) => {
            onActiveItemChange(element);
            event.stopPropagation();
          }}
        >
          <span class="component-name component-id">{element.id}</span>
          <el-form-item
            label={element.showLabel ? element.label : ''}
            label-width={labelWidth}
            required={element.required}
          >
            <render
              key={element.id}
              conf={element}
              onInput={(event) => {
                this.$set(element, 'value', event);
              }}
            />
          </el-form-item>
          {components.itemBtns.apply(this, arguments)}
        </el-col>
      );
    },
    rowItem(h, element) {
      const { onActiveItemChange } = this.$listeners;
      const className =
        this.activeItem.id === element.id
          ? 'drawing-item drawing-row-item active-from-item'
          : 'drawing-item drawing-row-item';
      return (
        <el-col class={className}>
          <el-row
            gutter={element.gutter}
            nativeOnClick={(event) => {
              onActiveItemChange(element);
              event.stopPropagation();
            }}
          >
            <span class="component-name">{element.id}</span>
            <div class="drag-wrapper" style="padding-left: 7.5px; padding-right: 7.5px;">
              {element.columns.map((item, index) => {
                return (
                  <el-col class="drag-col-wrapper" span={item.span}>
                    <draggable
                      class="drag-wrapper row-drag"
                      v-model={item.list}
                      animation="100"
                      group="componentsGroup"
                      onAdd={(e) => {
                        this.handlerAdd(e, item, element);
                      }}
                    >
                      {item.list.map((obj, objIndex) => {
                        return renderChildren.call(this, h, obj, element);
                      })}
                    </draggable>
                  </el-col>
                );
              })}
            </div>
          </el-row>
          {components.itemBtns.call(this, h, element)}
        </el-col>
      );
    },
    tableItem(h, element) {
      let className = '';
      className =
        this.activeItem.id === element.id
          ? 'drawing-item drawing-row-item active-from-item'
          : 'drawing-item drawing-row-item';
      const { onActiveItemChange } = this.$listeners;
      return (
        <el-col
          class={className}
          nativeOnClick={(event) => {
            onActiveItemChange(element);
            event.stopPropagation();
          }}
        >
          <span class="component-name" style="margin-bottom:15px">
            {element.id}
          </span>
          <fancy-table
            layoutArray={element.layoutArray}
            tdStyle={element.tdStyle}
            width={element.width}
            height={element.height}
            onSelectItem={(item) => {
              onActiveItemChange(item);
            }}
            scopedSlots={{
              default: (item) => {
                return (
                  <draggable
                    tag="div"
                    class="table__content row-drag"
                    v-model={item.td.columns}
                    animation="100"
                    group="componentsGroup"
                    onAdd={(e) => {
                      this.handlerTableAdd(e, item.td);
                      e.stopPropagation();
                    }}
                  >
                    {item.td.columns.map((obj) => {
                      return renderChildren.call(this, h, obj, item.td);
                    })}
                  </draggable>
                );
              }
            }}
          />
          {components.itemBtns.call(this, h, element)}
        </el-col>
      );
    },
    dynamicItem(h, element) {
      let className = '';
      className =
        this.activeItem.id === element.id
          ? className + 'drawing-item active-from-item'
          : className + 'drawing-item';
      const { onActiveItemChange } = this.$listeners;
      return (
        <el-col class={className}>
          <dynamic-table
            conf={element}
            activeItem={this.activeItem}
            nativeOnClick={(event) => {
              onActiveItemChange(element);
              event.stopPropagation();
            }}
          >
            <draggable
              tag="div"
              class="dynamic-table__content row-drag"
              ghost-class="dynamicGhost"
              v-model={element.columns}
              animation="100"
              group="componentsGroup"
              onAdd={(e) => {
                this.handlerDynamicAdd(e, element);
              }}
            >
              {element.columns.map((item, index) => {
                return (
                  <dynamic-table-item
                    item={item}
                    activeItem={this.activeItem}
                    onSelectItem={(evt, item) => {
                      onActiveItemChange(item);
                      evt.stopPropagation();
                    }}
                    onCopyItem={(evt) => {
                      this.handlerCopyItem(evt, element, index);
                      evt.stopPropagation();
                    }}
                    onDeleteItem={(evt) => {
                      this.handlerDeleteItem(evt, element, index);
                      evt.stopPropagation();
                    }}
                  />
                );
              })}
            </draggable>
          </dynamic-table>
          {components.itemBtns.call(this, h, element)}
        </el-col>
      );
    }
  };
  /**
   * 生成row的子选项
   */
  function renderChildren(h, element, parent) {
    const layout = layouts[element.layout];
    if (layout) {
      return layout.call(this, h, element, parent);
    }
    return layoutIsNotFound.call(this);
  }

  function layoutIsNotFound() {
    throw new Error(`没有与${this.element.layout}匹配的layout`);
  }
  export default {
    name: 'designItem',
    components: {
      render,
      draggable,
      dynamicTable,
      dynamicTableItem,
      fancyTable,
      fancyTableItem
    },
    props: {
      model: {
        type: Object,
        default: {}
      },
      activeItem: {
        type: Object,
        default: {}
      }
    },
    data() {
      return {
        activeComponent: this.activeItem
      };
    },
    render(h) {
      const layout = layouts[this.model.layout];
      if (layout) {
        return layout.call(this, h, this.model);
      }
      return layoutIsNotFound.call(this);
    },
    methods: {
      handlerAdd(evt, item, row) {
        if (evt.pullMode === 'clone') {
          if (!(evt.to.className.indexOf('row-drag') > -1 && this.activeItem.compType === 'row')) {
            item.list.splice(evt.newIndex, 0, this.activeItem);
          }
        } else {
          if (evt.item.className.indexOf('el-row') > -1) {
            //防止row嵌套
            const newIndex = evt.newIndex;
            const oldIndex = evt.oldIndex;
            const rowItem = item.list[newIndex];
            item.list.splice(newIndex, 1);
            this.$message.error('布局组件不允许被嵌套！');
            this.$emit('rowItemRollBack', rowItem, oldIndex); //还原到原先的列表中
            return false;
          }
        }
      },
      /**
       * 动态表单
       */
      handlerDynamicAdd(evt, item) {
        if (evt.pullMode === 'clone') {
          if (dynamicTableAllowedItems.includes(this.activeItem.compType)) {
            item.columns.splice(evt.newIndex, 0, this.activeItem);
          } else {
            this.$message.error('该组件不允许被放入动态表格内！');
          }
        } else {
          if (evt.item.className.indexOf('el-row') > -1) {
            //防止row嵌套
            const newIndex = evt.newIndex;
            const oldIndex = evt.oldIndex;
            const rowItem = item.columns[newIndex];
            item.columns.splice(newIndex, 1);
            this.$message.error('布局组件不允许放入动态表格！');
            this.$emit('rowItemRollBack', rowItem, oldIndex); //还原到原先的列表中
            return false;
          }
        }
      },
      handlerTableAdd(evt, td) {
        if (evt.pullMode === 'clone') {
          if (tableAllowedItems.includes(this.activeItem.compType)) {
            td.columns.splice(evt.newIndex, 0, this.activeItem);
          } else {
            this.$message.error('该组件不允许被放入表格内！');
          }
        }
      },
      handlerCopyItem(evt, element, index) {
        const item = element.columns[index];
        const clone = JSON.parse(JSON.stringify(item));
        let uId = 'fd_' + getSimpleId();
        clone.id = uId;
        clone._id = uId;
        element.columns.push(clone);
      },
      handlerDeleteItem(evt, element, index) {
        element.columns.splice(index, 1);
      }
    }
  };
</script>
